import pygame
import random
import sys
import numpy as np

# 初始化pygame
pygame.init()

# 游戏常量
WIDTH, HEIGHT = 600, 700
GRID_SIZE = 4
CELL_SIZE = 120
CELL_MARGIN = 10
GRID_OFFSET_X = (WIDTH - GRID_SIZE * (CELL_SIZE + CELL_MARGIN)) // 2
GRID_OFFSET_Y = 150  # 将棋盘向下移动50像素
FONT_SIZE = 36
TITLE_FONT_SIZE = 48

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
DARK_GRAY = (100, 100, 100)
BLUE = (0, 120, 255)
ORANGE = (255, 165, 0)
TURQUOISE = (64, 224, 208)
PURPLE = (128, 0, 128)
PINK = (255, 105, 180)

# 创建游戏窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("数字合并游戏")
# 更换字体为更现代的风格
font = pygame.font.SysFont('Comic Sans MS', FONT_SIZE, bold=True)
title_font = pygame.font.SysFont('Comic Sans MS', TITLE_FONT_SIZE, bold=True)

# 游戏状态
grid = np.zeros((GRID_SIZE, GRID_SIZE), dtype=int)
score = 0
game_over = False
won = False


def get_color(value):
    """根据数字值返回对应的颜色"""
    if value == 0:
        return GRAY, BLACK

    if 0 <= value < 10:
        return BLUE, WHITE
    elif 10 <= value < 20:
        return ORANGE, WHITE
    elif 20 <= value < 30:
        return TURQUOISE, WHITE
    elif 30 <= value < 40:
        return PURPLE, WHITE
    elif 40 <= value < 50:
        return PINK, WHITE
    elif 50 <= value < 60:
        return BLACK, BLUE
    elif 60 <= value < 70:
        return BLACK, ORANGE
    elif 70 <= value < 80:
        return BLACK, TURQUOISE
    elif 80 <= value < 90:
        return BLACK, PURPLE
    elif 90 <= value < 100:
        return BLACK, PINK
    else:
        rainbow_colors = [
            (255, 0, 0),    # 红
            (255, 69, 0),   # 橙红
            (255, 140, 0),  # 深橙
            (255, 215, 0),  # 金
            (255, 255, 0),  # 黄
            (154, 205, 50),  # 黄绿
            (0, 255, 0),    # 绿
            (0, 255, 127),  # 春绿
            (0, 255, 255),  # 青
            (0, 191, 255),  # 天蓝
            (0, 0, 255),    # 蓝
            (138, 43, 226),  # 蓝紫
            (148, 0, 211),  # 深紫
            (255, 0, 255),  # 粉紫
            (255, 20, 147)  # 深粉
        ]
        # 每5个数值变化一次颜色，使颜色变化更明显
        index = (value // 5) % len(rainbow_colors)
        return rainbow_colors[index], WHITE



def draw_gradient_rect(surface, rect, start_color, end_color, horizontal=True):
    """绘制渐变矩形"""
    if horizontal:
        for x in range(rect[0], rect[0] + rect[2]):
            ratio = (x - rect[0]) / rect[2]
            r = start_color[0] + ratio * (end_color[0] - start_color[0])
            g = start_color[1] + ratio * (end_color[1] - start_color[1])
            b = start_color[2] + ratio * (end_color[2] - start_color[2])
            pygame.draw.line(surface, (r, g, b), (x, rect[1]), (x, rect[1] + rect[3]))
    else:
        for y in range(rect[1], rect[1] + rect[3]):
            ratio = (y - rect[1]) / rect[3]
            r = start_color[0] + ratio * (end_color[0] - start_color[0])
            g = start_color[1] + ratio * (end_color[1] - start_color[1])
            b = start_color[2] + ratio * (end_color[2] - start_color[2])
            pygame.draw.line(surface, (r, g, b), (rect[0], y), (rect[0] + rect[2], y))


def add_random_tile():
    """在随机空位置添加1-5的数字"""
    empty_cells = [(i, j) for i in range(GRID_SIZE)
                   for j in range(GRID_SIZE) if grid[i, j] == 0]
    if empty_cells:
        i, j = random.choice(empty_cells)
        grid[i, j] = random.randint(1, 3)  # 1-5随机数，概率相同


def draw_grid():
    """绘制游戏网格"""
    screen.fill(WHITE)

    # 绘制标题
    title = title_font.render("BIG NUMBER", True, BLACK)
    screen.blit(title, (WIDTH // 2 - title.get_width() // 2, 20))

    # 绘制分数
    score_text = font.render(f"Score: {score}", True, BLACK)
    screen.blit(score_text, (20, 70))

    # 绘制目标
    target_text = font.render("Global:100", True, BLACK)
    screen.blit(target_text, (WIDTH - target_text.get_width() - 20, 70))

    # 绘制网格
    for i in range(GRID_SIZE):
        for j in range(GRID_SIZE):
            value = grid[i, j]
            bg_color, text_color = get_color(value)

            x = GRID_OFFSET_X + j * (CELL_SIZE + CELL_MARGIN)
            y = GRID_OFFSET_Y + i * (CELL_SIZE + CELL_MARGIN)

            if value >= 100:
                # 对于100以上的数字，绘制渐变色效果
                # 创建渐变色
                start_color = bg_color
                # 计算结束颜色（稍微变暗）
                end_color = (
                    max(0, bg_color[0] - 40),
                    max(0, bg_color[1] - 40),
                    max(0, bg_color[2] - 40)
                )
                # 绘制渐变矩形
                draw_gradient_rect(screen, (x, y, CELL_SIZE, CELL_SIZE), 
                                  start_color, end_color, False)
            else:
                pygame.draw.rect(screen, bg_color,
                                 (x, y, CELL_SIZE, CELL_SIZE), 0)

            if value > 0:
                # 如果是边框颜色模式，绘制边框
                if (50 <= value < 100):
                    pygame.draw.rect(screen, text_color,
                                     (x, y, CELL_SIZE, CELL_SIZE), 10)
                    text = font.render(str(value), True, WHITE)
                else:
                    text = font.render(str(value), True, text_color)

                screen.blit(text, (x + CELL_SIZE // 2 - text.get_width() // 2,
                                   y + CELL_SIZE // 2 - text.get_height() // 2))

    # 游戏结束或胜利提示
    if game_over:
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 128))
        screen.blit(overlay, (0, 0))

        if won:
            message = "You Win!"
        else:
            message = "Game Over!"

        text = title_font.render(message, True, WHITE)
        screen.blit(text, (WIDTH // 2 - text.get_width() //
                    2, HEIGHT // 2 - text.get_height() // 2))


def move_tiles(direction):
    """移动并合并数字"""
    global grid, score, won, game_over

    moved = False
    original_grid = grid.copy()

    # 根据方向处理移动
    if direction == "up":
        for j in range(GRID_SIZE):
            column = grid[:, j]
            new_column, column_moved, column_score = process_column(column)
            grid[:, j] = new_column
            moved = moved or column_moved
            score += column_score
    elif direction == "down":
        for j in range(GRID_SIZE):
            column = grid[:, j][::-1]  # 反转列
            new_column, column_moved, column_score = process_column(column)
            grid[:, j] = new_column[::-1]  # 反转回来
            moved = moved or column_moved
            score += column_score
    elif direction == "left":
        for i in range(GRID_SIZE):
            row = grid[i, :]
            new_row, row_moved, row_score = process_column(row)
            grid[i, :] = new_row
            moved = moved or row_moved
            score += row_score
    elif direction == "right":
        for i in range(GRID_SIZE):
            row = grid[i, :][::-1]  # 反转行
            new_row, row_moved, row_score = process_column(row)
            grid[i, :] = new_row[::-1]  # 反转回来
            moved = moved or row_moved
            score += row_score

    # 检查是否获胜
    if not won and np.any(grid >= 100):
        won = True

    # 如果移动了且游戏未结束，添加新方块
    if moved and not game_over:
        add_random_tile()

        # 检查游戏是否结束
        if not can_move():
            
            game_over = True


def process_column(column):
    """处理一列或一行的移动和合并"""
    moved = False
    new_column = np.zeros_like(column)
    score = 0
    pos = 0

    # 过滤掉0
    non_zero = column[column != 0]

    i = 0
    while i < len(non_zero):
        if i + 1 < len(non_zero) and abs(non_zero[i] - non_zero[i+1]) <= 3:
            # 可以合并
            merged_value = non_zero[i] + non_zero[i+1]
            new_column[pos] = merged_value
            score += merged_value
            pos += 1
            i += 2
            moved = True
        else:
            # 不能合并
            new_column[pos] = non_zero[i]
            if pos != i or column[pos] != new_column[pos]:
                moved = True
            pos += 1
            i += 1

    return new_column, moved, score


def can_move():
    """检查是否还有可能的移动"""
    # 检查是否有空格
    if np.any(grid == 0):
        return True

    # 检查是否有可以合并的相邻数字
    for i in range(GRID_SIZE):
        for j in range(GRID_SIZE):
            current = grid[i, j]
            # 检查右侧
            if j < GRID_SIZE - 1 and abs(current - grid[i, j+1]) <= 3:
                return True
            # 检查下方
            if i < GRID_SIZE - 1 and abs(current - grid[i+1, j]) <= 3:
                return True

    return False


def reset_game():
    """重置游戏"""
    global grid, score, game_over, won
    grid = np.zeros((GRID_SIZE, GRID_SIZE), dtype=int)
    score = 0
    game_over = False
    won = False
    add_random_tile()
    add_random_tile()


# 初始化游戏
reset_game()

# 游戏主循环
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if not game_over:
                if event.key == pygame.K_UP:
                    move_tiles("up")
                elif event.key == pygame.K_DOWN:
                    move_tiles("down")
                elif event.key == pygame.K_LEFT:
                    move_tiles("left")
                elif event.key == pygame.K_RIGHT:
                    move_tiles("right")
            if event.key == pygame.K_r:
                reset_game()

    draw_grid()
    pygame.display.flip()
    pygame.time.delay(50)

pygame.quit()
sys.exit()